package com.zndroid.base.ui.impl;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.IntRange;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.res.ResourcesCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewbinding.ViewBinding;

import com.zndroid.base.R;
import com.zndroid.base.callback.inner.mvp.IView;
import com.zndroid.base.widgets.HolderView;
import com.zndroid.netmonitor.NetType;
import com.zndroid.snackbar.Snackbar;
import com.zndroid.snackbar.SnackbarManager;
import com.zndroid.toast.Toaster;
import com.zndroid.utils.impl.ScreenUtil;

/**
 * ......................我佛慈悲....................
 * ......................_oo0oo_.....................
 * .....................o8888888o....................
 * .....................88" . "88....................
 * .....................(| -_- |)....................
 * .....................0\  =  /0....................
 * ...................___/`---'\___..................
 * ..................' \\|     |// '.................
 * ................./ \\|||  :  |||// \..............
 * .............../ _||||| -卍-|||||- \..............
 * ..............|   | \\\  -  /// |   |.............
 * ..............| \_|  ''\---/''  |_/ |.............
 * ..............\  .-\__  '-'  ___/-. /.............
 * ............___'. .'  /--.--\  `. .'___...........
 * .........."" '<  `.___\_<|>_/___.' >' ""..........
 * ........| | :  `- \`.;`\ _ /`;.`/ - ` : | |.......
 * ........\  \ `_.   \_ __\ /__ _/   .-` /  /.......
 * ....=====`-.____`.___ \_____/___.-`___.-'=====....
 * ......................`=---='.....................
 * ..................佛祖开光 ,永无BUG................
 *
 * @author lzy
 * base activity support net statue monitor
 */
@SuppressWarnings("unused")
public abstract class BaseActivity<VB extends ViewBinding, P extends BasePresenter> extends NetEnableActivity implements
        IView,
        HolderView.OnRetryButtonClickListener
{
    private P mPresenter;
    private VB viewBinding;
    private @NonNull final ScreenUtil screenUtil = new ScreenUtil();

    /**
     * current activity is died or not
     * @return true or false
     * */
    @Override
    public boolean isDied() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return this.isDestroyed();
        } else {
            return this.isFinishing();
        }
    }

    private boolean isPresenterReady() {
        return (null != mPresenter) && (mPresenter.isAttached());
    }

    @Override
    protected boolean isSupportNetworkMonitor() {
        return true;
    }

    /**
     * secure screen or not, if 'false' cannot screen capture， always used by pay or password element
     *
     * @return true or false
     * */
    protected boolean isScreenCaptureAble() {
        return true;
    }

    /**
     * translucent statusBar, default: false
     * */
    protected boolean isTranslucentStatusBar() {
        return false;
    }

    /**
     * override this fun if you want keep screen on
     *
     * @return true or false, default false and not keep screen on
     */
    protected boolean isKeepScreenOn() {
        return false;
    }

    /**
     * override this fun if you want keep fullscreen
     *
     * @return true or false, default false and not fullscreen
     */
    protected boolean isFullScreen() {
        return false;
    }

    /**
     * check is night model or not
     *
     * @return true or false
     * */
    protected boolean isNightMode() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return false;
        }

        int currentNightMode = getResources().getConfiguration().uiMode &
                Configuration.UI_MODE_NIGHT_MASK;
        return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
    }

    /**
     * get instance of current Presenter if you supply.
     * you can do something logic use it.
     * */
    protected P currentPresenter() {
        if (null == mPresenter) {
            throw new UnsupportedOperationException("pls implements #onSupplyPresenter() at first.F");
        }
        return mPresenter;
    }

    /**
     * get instance of current ViewBinding if you supply
     *
     * @return VB ViewBinding
     * */
    protected VB currentViewBinding () {
        return viewBinding;
    }

    @Override
    public View currentRootView() {
        if (null != viewBinding) {
            return viewBinding.getRoot();
        }
        return ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
    }

    @Override
    public Context currentContext() {
        return currentActivity().getApplicationContext();
    }

    @Override
    public FragmentActivity currentActivity() {
        return this;
    }

    @Override
    public Intent currentIntent() {
        return getIntent();
    }

    /**
     * support Day and Night model
     *
     * https://blog.csdn.net/u010257931/article/details/105042516/
     *
     * color: create dir 'values-night' on 'res' and create 'colors.xml'，
     * drawable: create dir 'drawable-night' on 'res'
     * theme: create dir 'values-night' on 'res' and create 'themes.xml' or use Theme.AppCompat.DayNight
     * */
    @AppCompatDelegate.NightMode
    protected int onSupplyNightModel() {return AppCompatDelegate.MODE_NIGHT_NO;}

    /**
     * if you use Presenter to implements logic, Override it at first.
     * */
    protected P onSupplyPresenter() {
        return createPresenter();
    }

    /**
     * 采用反射的形式（避免让子类进行实例化，繁琐）
     * */
    protected P createPresenter() { 
        ParameterizedType type = (ParameterizedType)(getClass().getGenericSuperclass()); 
        if(type == null){ 
            return null; 
        } 
        Type[] typeArray = type.getActualTypeArguments(); 
        if(typeArray.length == 0){ 
            return null; 
        } 
        Class<P> clazz = (Class<P>) typeArray[0]; 
        try { 
            return clazz.newInstance(); 
        } catch (IllegalAccessException e) { 
            e.printStackTrace(); 
        } catch (InstantiationException e) { 
            e.printStackTrace(); 
        } 
        return null; 
    } 

    /**
     * supply layout_id of subclass
     *
     * @deprecated instead of {@link #onSupplyViewBinding(LayoutInflater)}, strongly recommended replace it.
     * @return LayoutRes id
     * */
    @Deprecated
    @LayoutRes
    @SuppressWarnings("DeprecatedIsStillUsed")
    protected int onSupplyLayoutId() {return -1;}

    /**
     * must supply ViewBinding instance if current page will be impl layout.<br>
     * you should enable support 'ViewBinding' at your module 'build.gradle' like this:
     * <code>
     *     // Android Studio 3.6.0
     *     android {
     *         ...
     *         viewBinding {
     *             enabled = true
     *         }
     *     }
     *
     *     // Android Studio 4.0 +
     *     android {
     *         ...
     *         buildFeatures {
     *             viewBinding = true
     *         }
     *     }
     * </code>
     *
     *
     * @param layoutInflater layoutInflater
     * @return VB instance of ViewBinding
     * */
    protected abstract VB onSupplyViewBinding(@NonNull LayoutInflater layoutInflater);

    /**
     * support change StatusBar color<br> only support pure color, if your want use gradient color ,
     * called {@link ScreenUtil#setStatusBarGradientColor(Activity, View)} pls.<br>
     * like this:
     * <pre>
     *     {@code
     *          @Override
     *          protected void doOnResume() {
     *              super.doOnResume();
     *              XUtils.create().screenUtil().setStatusBarGradientColor(this, currentViewBinding().toolbar);
     *          }
     *     }
     * </pre>
     * Attention: <br>
     *     If you use {@link BaseActivity} change StatusBar color, and contains {@link BaseFragment},
     *     StatusBar color valid at it's activity, if you want valid at child of {@link BaseFragment},
     *     you will be set 'true' of {@link BaseFragment#isValidateStatueBarColorOfFragment()} <br>
     *
     *  See Also: <br>
     *  {@link com.zndroid.base.ui.common.CommonViewPageActivity}
     *  {@link com.zndroid.base.ui.common.CommonNavigationTabActivity}
     *  {@link com.zndroid.base.ui.common.CommonViewPageFragment}
     * */
    @ColorInt
    protected int onSupplyStatusBarColor() { return ResourcesCompat.getColor(getResources(), android.R.color.black, getTheme());}

    /**
     * support {@link androidx.appcompat.widget.Toolbar}
     *
     * notice:change Theme must already has not an action bar
     * */
    protected Toolbar onSupplyToolBar() {return null;}

    @Override
    public HolderView onSupplyPlaceholder() {
        return null;
    }

    /**
     * Net statue monitor
     *
     * @param isConnect true or false
     * @param type net type {@link NetType}
     * @param signalLevel a single integer from 0 to 4 representing the general signal quality.
     *      This may take into account many different radio technology inputs.
     *      0 represents very poor signal strength
     *      while 4 represents a very strong signal strength
     * */
    protected void onBackNetChanged(boolean isConnect, String type, int signalLevel) {

    }

    /**
     * Net statue monitor
     *
     * @param isConnect true or false
     * @param type net type {@link NetType}
     * */
    protected void onBackNetConnected(boolean isConnect, String type) {

    }

    @Override
    public void onBackRetryClicked(View v) {

    }

    @Override
    public void onNetChanged(boolean isConnect, String type, int signalLevel) {
        //I think subclass to deal change
        if (isSupportNetworkMonitor()) {
            onBackNetChanged(isConnect, type, signalLevel);
        }
    }

    @Override
    public void onNetConnected(boolean isConnect, String type) {
        if (isSupportNetworkMonitor()) {
            showNetStatues(isConnect, type);
            onBackNetConnected(isConnect, type);
        }
    }

    /**
     * day or night model
     *
     * @param isNight true is night, or is day
     * */
    protected void toChangeNightModel(boolean isNight) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            if (isNight && !isNightMode()) {
                getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            } else if (!isNight && isNightMode()) {
                getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            } else {
                return;
            }

            overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);

            recreate();
        }
    }

    /**
     * hide or show ActionBar
     * @param hide true or false
     * */
    public void toChangeActionBar(boolean hide) {
        if (null != getSupportActionBar()) {
            if (hide) {
                getSupportActionBar().hide();
            } else {
                getSupportActionBar().show();
            }
        } else {
            logW("action bar not exist.");
        }
    }

    /**
     * hide or show StatusBars
     * @param hide true or false
     * */
    public void toChangeStatusBars(boolean hide) {
        if (hide) {
            screenUtil.hideStatusBar(this);
        } else {
            screenUtil.showStatusBar(this);
        }
    }

    /**
     * change statusBar color, only support pure color
     * @param color colorInt
     * @param alpha alpha
     * */
    public void toChangeStatusBarColor(@ColorInt int color, @IntRange(from = 0L,to = 255L) int alpha) {
        screenUtil.setStatusBarColor(this, color, alpha);
    }

    /**
     * transparent StatusBar
     * */
    public void toTransparentStatusBar() {
        screenUtil.transparentStatusBar(this);
    }

    /**
     * hide or show NavigationBars
     * @param hide true or false
     * */
    public void toChangeNavigationBars(boolean hide) {
        if (hide) {
            screenUtil.hideNavigationBar(this);
        } else {
            screenUtil.showNavigationBar(this);
        }
    }

    /**
     * invalidate keep screen on, you can call this to clear keep screen on flag
     */
    protected void toNotKeepScreenOn() {
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    /**
     * invalidate fullscreen, you can call this to clear fullscreen on flag
     */
    protected void toNotFullScreen() {
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

    /**
     * to support ScreenCapture or not
     *
     * @param enable true:support false not support
     * */
    protected void toScreenCaptureEnable(boolean enable) {
        if (!enable) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
        } else {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
        }
    }

    @Override
    public void toDismissPlaceholder() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().showSuccess();
        }
    }

    @Override
    public void onBackPressed() {
        doPreOnBackPressed();
        super.onBackPressed();
        doOnBackPressed();
    }

    @Override
    protected void onStart() {
        super.onStart();
        doOnStart();
    }

    @Override
    protected void onRestart() {
        doOnRestart();
        super.onRestart();
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        //Day or Night model
        //[bug fixed]by lazy at 2020/12/16 写在 super.onCreate() 之前防止调用多次
        AppCompatDelegate.setDefaultNightMode(onSupplyNightModel());

        if (null != onSupplyPresenter()) {
            //call at first
            mPresenter = onSupplyPresenter();
            mPresenter.attachView(this);
        }

        super.onCreate(savedInstanceState);

        //view binding
        viewBinding = onSupplyViewBinding(getLayoutInflater());

        if (null == viewBinding) {
            setContentView(onSupplyLayoutId());
        } else {
            setContentView(viewBinding.getRoot());
        }

        //LifeCycle
        if (isPresenterReady()) {
            getLifecycle().addObserver(mPresenter);
        }

        //////for inner function start

        //ToolBar
        if (null == getSupportActionBar()) {
            setSupportActionBar(onSupplyToolBar());
        } else {
            logW("Tips from " + BaseActivity.class.getSimpleName() +
                    ": This Activity already has an action bar, \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +
                    "  If you want instead of [ToolBar], Do not request 'Window.FEATURE_SUPPORT_ACTION_BAR' \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +
                    "  and set '<item name=\"android:windowActionBar\">false</item>' in your theme style.");
        }
        //KeepScreenOn ?
        if (isKeepScreenOn()) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        } else {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
        //FullScreen ?
        if (isFullScreen()) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
        //ScreenCapture able?
        if (!isScreenCaptureAble()) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
        } else {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
        }
        //////for inner function end

        doOnCreate(savedInstanceState);

        //all view ok
        doOnInitViewAfterAllReady(currentRootView());
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        doSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
    }

    @Override
    protected void onResume() {
        super.onResume();

        //StatusBar fixed：当跳转其他改变状态栏的页面返回时，当前页面的状态栏不会恢复的bug
        if (isTranslucentStatusBar()) {
            screenUtil.transparentStatusBar(this);
        } else {
            screenUtil.setStatusBarColor(this, onSupplyStatusBarColor());
        }
        doOnResume();
    }

    @Override
    protected void onResumeFragments() {
        super.onResumeFragments();
        doOnResumeFragments();
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
    }

    @Override
    protected void onPause() {
        doOnPause();
        super.onPause();
    }

    @Override
    protected void onStop() {
        doOnStop();
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        doOnDestroy();
        super.onDestroy();

        if (isPresenterReady()) {
            mPresenter.detachView();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        doOnActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public void onContentChanged() {
        super.onContentChanged();
        doOnInitView(currentRootView());
    }

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        doOnUserInteraction();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        doOnNewIntent(intent);
        super.onNewIntent(intent);
    }

    @Override
    protected void onNightModeChanged(@AppCompatDelegate.NightMode int mode) {
        super.onNightModeChanged(mode);
        doOnNightModeChanged(mode);
    }

    /**
     * onPreBackPressed
     * */
    protected void doPreOnBackPressed() {}

    /**
     * onBackPressed
     * */
    protected void doOnBackPressed() {}

    /**
     * onStart
     * */
    protected void doOnStart() {}

    /**
     * onRestart
     * */
    protected void doOnRestart() {}

    /**
     * onCreate
     * */
    protected void doOnCreate(@Nullable Bundle savedInstanceState) {}

    /**
     * onSaveInstanceState
     * */
    protected void doSaveInstanceState(@NonNull Bundle outState) {}

    /**
     * onResume
     * */
    protected void doOnResume() {}

    /**
     * 将onResume() 分发给fragment。注意，为了更好的和旧版本兼容，这个方法调用的时候，
     * 依附于这个activity的fragment并没有到resumed状态。着意味着在某些情况下，前面的状态可能被保存了，
     * 不允许fragment transaction再修改状态。为了在状态上正确 的和fragment交互，
     * 你应该重写onResumeFragments()而不是onResume() 。
     * */
    protected void doOnResumeFragments() {}

    /**
     * onPause
     * */
    protected void doOnPause() {}

    /**
     * onStop
     * */
    protected void doOnStop() {}

    /**
     * onDestroy
     * */
    protected void doOnDestroy() {}

    /**
     * onActivityResult
     * */
    protected void doOnActivityResult(int requestCode, int resultCode, @Nullable Intent data) {}

    /**
     * onConfigurationChanged
     * */
    protected void doOnConfigurationChanged(@NonNull Configuration newConfig) {}

    /**
     * onNightModeChanged
     * */
    protected void doOnNightModeChanged(@AppCompatDelegate.NightMode int mode) {}

    /**
     * user interacting with current activity
     * Activity 无论分发按键事件、触摸事件或者轨迹球事件都会调用 Activity#onUserInteraction()。如果想知道用户用某种方式和你正在运行的 activity 交互，可以重写 Activity#onUserInteraction()。所有调用 Activity#onUserLeaveHint() 的回调都会首先回调 Activity#onUserInteraction() 。
     * Activity 在分发各种事件的时候会调用该方法，注意：启动另一个 activity ,Activity#onUserInteraction()会被调用两次，一次是 activity 捕获到事件，另一次是调用 Activity#onUserLeaveHint() 之前会调用 Activity#onUserInteraction() 。
     * 可以用这个方法来监控用户有没有与当前的 Activity 进行交互。
     * */
    protected void doOnUserInteraction() {}

    /**
     * onNewIntent
     * */
    protected void doOnNewIntent(Intent intent) {}

    /**
     * 此回调方法适用于：布局中控件都是静态布局好的状态，没有动态地在父布局的基础上继续添加其他子布局。否则，
     * 当想在此初始化【在父布局的基础上继续添加其他子布局】中的控件时，会抛出空指针异常，
     * 因为此方法回调的时候，【在父布局的基础上继续添加其他子布局】中的动态子布局还没被append父布局中，
     * 建议使用 {@link #doOnInitViewAfterAllReady(View)}，此方法在后期版本中仍然保留，以适用于不同情况。<br>
     *
     * you can init View(findViewById) here，but, all child view is static layout
     * */
    protected void doOnInitView(View rootView) {}

    /**
     * you can init View(findViewById) here, all view is ready.
     * See ALso: {@link #doOnInitView(View)}
     * */
    protected void doOnInitViewAfterAllReady(View rootView) {}

    @Override
    public void showEmptyData() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showEmpty();
        }
    }

    @Override
    public void showErrorData() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showError();
        }
    }

    @Override
    public void showToast(String msg) {
        if (isDied()) {return;}

        if (!Toaster.isInit()) {
            Toaster.init(getApplication());
        }
        Toaster.show(msg);
    }

    private void showNetStatues(boolean isConnect, @NetType String type) {
        //实际业务场景【通常】只需要在无网络的情况下给与提示，子类可复写实现方式
        if (!isConnect) {
            SnackbarManager.show(
                    Snackbar.with(this)
                            .colorResource(R.color.base_color_red)
                            .position(Snackbar.SnackbarPosition.TOP)
                            .actionListener(Snackbar::dismiss)
                            .text(R.string.base_txt_net_disconnected_tip)
                    , ((ViewGroup) findViewById(android.R.id.content)));
        }

    }

    @Override
    public void showNetError() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showBadNet();
        }
    }

    @Override
    public void showLoading() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showWait();
        }
    }

    @Override
    public void showLoading(String msg) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showWait(msg);
        }
    }

    @Override
    public void showLoading(String msg, boolean cancelable) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showWait(msg, cancelable);
        }
    }

    @Override
    public void show404() {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().show404();
        }
    }

    @Override
    public void showTip(@DrawableRes int resId, String msg) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showTip(resId, msg);
        }
    }

    @Override
    public void showTip(@DrawableRes int resId, String msg, boolean isShowRetry) {
        if (null != onSupplyPlaceholder()) {
            onSupplyPlaceholder().setOnRetryButtonClickListener(this);
            onSupplyPlaceholder().showTip(resId, msg, isShowRetry);
        }
    }

    /**
     * jump other intent page<br>
     *
     * See Also: {@link #toActivityCallBackAble(Intent)}
     *
     * @param clazz class will be jump
     * */
    @Override
    public void jumpTo(@NonNull Class<?> clazz) {
        jumpTo(new Intent(this, clazz));
    }

    /**
     * jump other intent page<br>
     *
     * See Also: {@link #toActivityCallBackAble(Intent)}
     *
     * @param intent intent will be jump
     * */
    @Override
    public void jumpTo(@Nullable Intent intent) {
        startActivity(intent);
    }

    /**
     * jump other intent page<br>
     *
     * See Also: {@link #toActivityCallBackAble(Intent)}
     *
     * @param intent intent will be jump
     * @param bundle params with intent
     * */
    @Override
    public void jumpTo(@Nullable Intent intent, @Nullable Bundle bundle) {
        if (null != intent) {
            intent.putExtras(bundle);
        }
        jumpTo(intent);
    }

    @Override
    public void jumpTo(@Nullable Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode);
    }

    @Override
    public void jumpTo(@Nullable Intent intent, @Nullable Bundle bundle, int requestCode) {
        if (null != intent) {
            intent.putExtras(bundle);
        }

        startActivityForResult(intent, requestCode);
    }

    public void jumpToFromFragment(@NonNull Fragment fragment,
                                   @SuppressLint("UnknownNullness") Intent intent, int requestCode) {
        startActivityFromFragment(fragment, intent, requestCode);
    }

    public void jumpToFromFragment(@NonNull Fragment fragment,
                                   @SuppressLint("UnknownNullness") Intent intent, @Nullable Bundle bundle,  int requestCode) {
        if (null != intent) {
            intent.putExtras(bundle);
        }
        startActivityFromFragment(fragment, intent, requestCode);
    }

    @Override
    public void recreate() {
        //[bug fixed]by lazy at 2020/12/17 调用recreate()【夜间模式切换】时，
        //如果Activity直接通过add创建fragment，Activity恢复时会导致fragment重叠
        //可以根据所需，子类复写该方法，具体实现特定逻辑，目前是都清除
        try {
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            for (Fragment fragment : getSupportFragmentManager().getFragments()) {
                transaction.remove(fragment);
            }
            transaction.commitAllowingStateLoss();
        } catch (Exception e) {
            //nothing
        }
        super.recreate();
    }

    @Override
    public Bundle getBundleArgs() {
        if (null != getIntent()) {
            return getIntent().getExtras();
        }
        return null;
    }
}
